package com.wutma.friend.service.question.Impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.wutma.common.core.constants.Constants;
import com.wutma.common.core.domain.TableDataInfo;
import com.wutma.friend.domain.question.entity.Question;
import com.wutma.friend.domain.question.dto.QuestionDTO;
import com.wutma.friend.domain.question.vo.QuestionDetailVO;
import com.wutma.friend.domain.question.vo.QuestionESVO;
import com.wutma.friend.domain.question.vo.QuestionVO;
import com.wutma.friend.manager.QuestionCacheManager;
import com.wutma.friend.manager.QuestionEsManager;
import com.wutma.friend.mapper.question.QuestionMapper;
import com.wutma.friend.service.question.IQuestionService;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

@Service
public class QuestionServiceImpl implements IQuestionService {

    @Autowired
    private RestHighLevelClient esClient;

    @Autowired
    private QuestionMapper questionMapper;

    @Autowired
    private QuestionCacheManager questionCacheManager;

    @Autowired
    private QuestionEsManager questionEsManager;

    @Override
    public TableDataInfo list(QuestionDTO questionDTO) {

        try {
            // 1. 准备Request对象
            SearchRequest request = new SearchRequest(Constants.ES_INDEX);
            // 2. 准备DSL
            // 2.1 构建BooleanQuery
            buildBasicQuery(questionDTO, request);
            // 2.2 分页
            request.source().from((questionDTO.getPageNum() - 1) * questionDTO.getPageSize()).size(questionDTO.getPageSize());
            // 3. 发送请求
            SearchResponse response = esClient.search(request, RequestOptions.DEFAULT);
            // 4. 解析结果并返回
            return handleResponse(response);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public QuestionDetailVO detail(Long questionId) {

        // 先从ES中查询结果
        QuestionDetailVO questionDetailVO = new QuestionDetailVO();
        QuestionESVO questionEsVO = questionEsManager.getQuestionEsVO(questionId);
        if (questionEsVO != null) {
            BeanUtil.copyProperties(questionEsVO, questionDetailVO);
            return questionDetailVO;
        }
        // ES中查询不到，则从数据库中获取
        Question question = questionMapper.selectById(questionId);
        if (question == null) {
            return null;
        }
        BeanUtil.copyProperties(question, questionDetailVO);
        // 数据库存在，刷新ES
        questionEsManager.refreshES();
        return questionDetailVO;
    }

    @Override
    public String preQuestion(Long questionId) {
        checkQuestionList();
        return questionCacheManager.preQuestion(questionId).toString();
    }

    @Override
    public String nextQuestion(Long questionId) {
        checkQuestionList();
        return questionCacheManager.nextQuestion(questionId).toString();
    }

    private void checkQuestionList() {
        Long total = questionCacheManager.getQuestionListSize();
        if (total == null || total <= 0) {
            // 刷新题目缓存
            questionCacheManager.refreshCache();
        }
    }

    private TableDataInfo handleResponse(SearchResponse response) {
        // 4. 解析结果
        // 4.1 获取总条数
        SearchHits searchHits = response.getHits();
        long total = searchHits.getTotalHits().value;
        if (total <= 0) {
            // 若ES中查询不到，则从数据库中获取，并更新到ES中
            List<QuestionESVO> questionESVOS = questionEsManager.refreshES();
            if (questionESVOS.isEmpty()) {
                return TableDataInfo.empty();
            }
            else {
                List<QuestionVO> questionVOS = BeanUtil.copyToList(questionESVOS, QuestionVO.class);
                return TableDataInfo.success(questionVOS, questionVOS.size());
            }
        }
        // 进入此次表示ES中能够正确查询到数据，进行解析
        // 4.2 文档数组
        SearchHit[] hits = searchHits.getHits();
        // 4.3 返回结果列表
        List<QuestionESVO> questionESVOList = new ArrayList<>();
        for (SearchHit hit : hits) {
            // 获取文档Source
            String json = hit.getSourceAsString();
            // 反序列化
            QuestionESVO questionESVO = JSON.parseObject(json, QuestionESVO.class);
            // 将结果添加到数组中
            questionESVOList.add(questionESVO);
        }

        List<QuestionVO> questionVOS = BeanUtil.copyToList(questionESVOList, QuestionVO.class);
        // 封装结果返回
        return TableDataInfo.success(questionVOS, total);
    }

    private void buildBasicQuery(QuestionDTO questionDTO, SearchRequest request) {

        // 1. 原始查询
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();

        Integer difficulty = questionDTO.getDifficulty();
        String keyword = questionDTO.getKeyword();
        if (difficulty == null && StrUtil.isEmpty(keyword)) {
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        // 关键字搜索
        if (StrUtil.isNotEmpty(keyword)) {
            boolQuery.must(QueryBuilders.matchQuery(Constants.ES_FIELD_ALL, keyword));
        }
        // 难度
        if (difficulty != null) {
            boolQuery.filter(QueryBuilders.termQuery(Constants.ES_FIELD_DIFFICULTY, difficulty));
        }
        // 默认按创建时间排序
        request.source().sort(Constants.ES_FIELD_CREATE_TIME, SortOrder.DESC);
        // 将条件放入source
        request.source().query(boolQuery);
    }



}
